Skip to content

Conversation

@netmindz
Copy link
Member

@netmindz netmindz commented Nov 8, 2025

C6 needs the newer ESP-IDF, so have one branch for those changes and keep this one just for the C6 specific things

Building on top of V5

Inspired by C6 Experiments

Help Us with Testing

If you own a C6 or C5 board, we like to hear from your experiences! Basic functions are working on our dev boards, but any problem you find will help us stabilize the C5/C6 versions faster. If you find an error, please create an issue ticket (bug report).

Important: Our V5 Branch is Experimental (early stage of development)

  • Firmare you find here is absolutely not suitable for "production" use
  • Basic functions are working already
  • Make sure you have access to USB, to recover a boot-looping device if necessary
  • Expect bugs, expect unexpected crashes, expect network connectivity problems, expect flickering LEDs
  • Some features had to be disabled temporarily, because they still don't build with the new framework
  • analog LEDs may or may not work
  • OTA update is not yet possible on some boards
  • Ethernet support is totally untested
  • Some Usermods still don't compile
  • Audioreactive is not ported yet
  • DMX serial is not ported yet

You can find a summary of currently open ends here (open ends for C5, C6), here (modernization opportunities) and here (generic problems with V5).

Using Development Tools (VSCode) - recommended

You can build your own C5 or C6 firmware using our standard development environment (VSCode+platformio) on your own computer. Use Platformio "upload and monitor" to write firmware to your board.

image

Experimental Binaries

In case you are not feeling comfortable using development tools, you can find some firmware binaries that are automatically created by GitHub after each commit.

  • scroll down to the box "All checks have passed"
  • expand the box with the icon on the right side
  • click on a build that matches your board, for example WLED CI / wled_build / Build Environments (esp32c6dev_4MB) (push)
  • click on "Summary"
  • scroll down until you see "Artifacts"
  • download the firmware.bin for your board
image image

Help Us with Coding

Helpful information and migration guidance

coding guides

We should make sure that the "V5" branch will still compile for "V4" as a backup solution.
When adding code that only works in the new framework, it should be conditionally compiled, like in the examples below

  • "V5" code only for esp32-P4 or esp32-C6:
 #if defined(CONFIG_IDF_TARGET_ESP32C6)
    // https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/gpio.html
    // strapping pins: 4, 5, 8, 9
    if (gpio > 11 && gpio < 14) return false;     // 12-13 USB-JTAG
    if (gpio > 23 && gpio < 31) return false;     // 24-30 SPI FLASH
#elif defined(CONFIG_IDF_TARGET_ESP32P4)
    // strapping pins: 34,35,36,37,38
    if (             gpio <   2) return false;     // NC
    if (gpio > 13 && gpio <  20) return false;     // ESP-Hosted WiFi pins
    if (gpio > 23 && gpio <  26) return false;     // USB Pins
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
  // .... existing code
#else
  // .... existing code
#endif
  • "V5" code that is not specific to new boards
    #if defined(ESP_IDF_VERSION) && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
      ledcAttach(pwmPin, 25000, 8);  // New API: ledcAttach(pin, freq, resolution)
    #else
      ledcSetup(pwmChannel, 25000, 8);
      // attach the channel to the GPIO to be controlled
      ledcAttachPin(pwmPin, pwmChannel);
    #endif

related

Summary by CodeRabbit

  • New Features

    • Official ESP32‑C5/C6 family support; UI shows WiFi band + channel and adds a WiFi‑band selector; MAC fallback when hardware MAC is missing.
  • Bug Fixes / Compatibility

    • Harmonized touch, parallel-output, DMX, PSRAM/memory, pin-safety and timing across ESP32 variants; improved 5GHz handling and TX power limits; OTA/bootloader checks updated for C5/C6.
  • Chores

    • Expanded build matrix and defaults for C5/C6, noted FastLED patch, centralized board capability flags, and updated editor recommendations.

netmindz and others added 3 commits November 8, 2025 13:33
due to Arduino 3.0.1, a few updated libraries are required:
* Tasmota Platform - official platfomio lacks arduino support for C6
* FastLED (latest + C6 build patches)
* AsyncTCP (latest + C6 build patches)
* AsyncWebServer (latest + C6 build patches)
* NeoPixelBus (lastest)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 8, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds ESP32-C5 and ESP32-C6 build environments and PlatformIO config; expands many CONFIG_IDF_TARGET_* guards across sources so C5/C6 (and P4) are treated like C3 for I2S/touch/PSRAM/DMX/pin-safety and other platform-specific logic.

Changes

Cohort / File(s) Summary
PlatformIO / build environments
platformio.ini
Adds [esp32c6] and [esp32c5] generic sections, multiple new envs (esp32c6dev_8MB/4MB, esp32c5dev, qspi variants), default_envs update, per-env partitions/flash/memory hints, and lib_deps note for patched FastLED.
Bus / I2S / PWM / RMT
wled00/bus_wrapper.h, wled00/bus_manager.cpp, wled00/FX_fcn.cpp, wled00/FX.h
Expanded preprocessor guards to include ESP32C5/C6/P4 alongside C3; disabled parallel I2S paths on those targets; added C5-specific LEDC duty register access; adjusted dithering/LEDC mutex and esp32RMTInvertIdle early-returns.
Touch / Buttons / Pin safety
wled00/button.cpp, wled00/pin_manager.cpp
Touch/button guards extended to exclude ESP32C5/C6/P4; added per-target pin-safety rules (SPI flash / USB-JTAG reserved GPIO ranges) for ESP32C5 and ESP32C6.
PSRAM / allocation / constants
wled00/util.cpp, wled00/const.h
Broadened PSRAM and allocation guards to include C3/C5/C6/P4 (and others); aligned MAX_LEDS/MAX_LED_MEMORY and WLED_MAX_DIGITAL_CHANNELS for C5/C6 with C3.
Config / JSON / OTA / network
wled00/cfg.cpp, wled00/json.cpp, wled00/ota_update.cpp, wled00/network.cpp, wled00/udp.cpp
Gated parallel-I2S flags for C5/C6/P4; serializeInfo sets arch="esp32" for CONFIG_IDF_TARGET_ESP32; added wifi channel/band (5GHz detection) and UDP node-type handling for C5/C6; added explicit ESP32-C5 bootloader chip-id checks and blocks updates.
DMX / dependencies
wled00/dmx_output.cpp, wled00/src/dependencies/dmx/*
Added ESP32C5 to DMX init/preprocessor guards so DMX code compiles/initializes for C5 alongside existing targets.
Audio / FX / particle systems / UI
usermods/audioreactive/audio_reactive.cpp, wled00/FXparticleSystem.cpp, wled00/data/index.js, wled00/FX_fcn.cpp
Extended guards to include C5/C6 for audio/I2S/PDM branches and FX fast-paths; updated UI device mapping to recognize ESP32-C5/C6; added WiFi band row in UI JSON rendering.
Build scripts / metadata / tooling
pio-scripts/set_metadata.py, .vscode/extensions.json
set_metadata now injects CPPDEFINES into env in-place and prints debug info (repo, WLED_VERSION); VSCode recommendations updated to include PlatformIO Arduino extension.
Misc / small fixes
wled00/wled.cpp, wled00/wled.h, wled00/set.cpp, wled00/mbedtls_sha1_shim.cpp, wled00/NodeStruct.h, wled00/improv.cpp, wled00/data/index.js, wled00/udp.cpp
MAC fallback via esp_read_mac for ESP32, added C5 5GHz logging, widened RX/TX/config guards to include C5/C6/P4, narrowed mbedTLS shim IDF gate, EOF newline fix, and a small bounds-check change in findWiFi.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • netmindz
  • willmmiles
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective: adding ESP32-C6 and ESP32-C5 MCU support to ESP-IDF V5 builds. It is specific, clear, and directly reflects the primary changes throughout the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch V5-C6

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

platformio.ini Outdated
Comment on lines 14 to 28
;nodemcuv2
;esp8266_2m
;esp01_1m_full
;nodemcuv2_160
;esp8266_2m_160
;esp01_1m_full_160
;nodemcuv2_compat
;esp8266_2m_compat
;esp01_1m_full_compat
;esp32dev
;esp32dev_debug
;esp32_eth
;esp32_wrover
; lolin_s2_mini ;; TODO: disabled NeoEsp32RmtMethodIsr
esp32c3dev
;esp32c3dev
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: revert before merge, here to save CI build time

@netmindz
Copy link
Member Author

netmindz commented Nov 8, 2025

@softhack007 I've started trying to cherry-pick your changes over, quite a few don't apply due to the changes with MM, but I'll try and resolve the merge conflicts for those that are simple

* more debug output
* added my own fork of FastLED ( looks like more bugs to solve ....)
@softhack007
Copy link
Member

@softhack007 I've started trying to cherry-pick your changes over, quite a few don't apply due to the changes with MM, but I'll try and resolve the merge conflicts for those that are simple

@netmindz thanks, I'll try to help once I'm finished with some open ends in WLED-MM 😁 december

@netmindz
Copy link
Member Author

netmindz commented Nov 8, 2025

Possibly also worth looking at #4626 to see if there are any changes there that are helpful

@softhack007 softhack007 added this to the 0.17.0 milestone Nov 18, 2025
@softhack007 softhack007 mentioned this pull request Nov 18, 2025
@netmindz

This comment was marked as resolved.

@softhack007

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@softhack007

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
wled00/FX_fcn.cpp (1)

1194-1211: ⚠️ Potential issue | 🟠 Major

Fix single‑I2S DMA memory estimation for ESP32/S2.

usesI2S still assumes single‑I2S is the first digital bus (and doesn’t account for S2 single‑I2S), which underestimates maxI2S once multiple digital buses are configured. With single‑I2S now mapped to the last bus, the DMA memory estimate should key off that bus index to avoid allowing oversized configs through the MAX_LED_MEMORY check.

🔧 Suggested adjustment (align single‑I2S bus index)
-    `#if` defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
-    const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1));
-      `#elif` defined(CONFIG_IDF_TARGET_ESP32S2)
-    const bool usesI2S = (useParallelI2S && digitalCount <= 8);
+    `#if` defined(CONFIG_IDF_TARGET_ESP32)
+    const unsigned singleI2SBus = 9; // bus 8 (last) when single I2S
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == singleI2SBus);
+      `#elif` defined(CONFIG_IDF_TARGET_ESP32S3)
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1);
+      `#elif` defined(CONFIG_IDF_TARGET_ESP32S2)
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 5); // bus 4 (last) when single I2S
Based on learnings: In WLED PR `#5267`, the single‑I2S bus moved to the last bus (ESP32 bus 8, ESP32‑S2 bus 4), so memory calculations must account for that specific bus index.
wled00/wled.h (2)

158-165: ⚠️ Potential issue | 🟡 Minor

DMX error message should mention C61.

The guard includes ESP32‑C61, but the compile‑time error text doesn’t.

✏️ Suggested message update
-  `#error` "DMX output is not supported on ESP32-C5/C6/P4 (esp_dmx library excluded)"
+  `#error` "DMX output is not supported on ESP32-C5/C6/C61/P4 (esp_dmx library excluded)"
-  `#error` "DMX output is not supported on ESP32-C5/C6/P4 (esp_dmx library excluded)"
+  `#error` "DMX output is not supported on ESP32-C5/C6/C61/P4 (esp_dmx library excluded)"

Also applies to: 480-483


334-344: ⚠️ Potential issue | 🔴 Critical

Guard RX/TX usage for non‑classic ESP32 targets.

The current guard logic has a flaw: for non-classic ESP32s (S2/S3/C3/C5/C6/C61/P4), the condition !defined(CONFIG_IDF_TARGET_ESP32) short-circuits the OR to TRUE, bypassing the RX/TX existence check. Since some Arduino-ESP32 board variants don't define these macros, this will cause compilation failures. Require explicit RX/TX presence for all ESP32 targets:

-#if defined(ARDUINO_ARCH_ESP32) && (!defined(CONFIG_IDF_TARGET_ESP32) || (defined(RX) && defined(TX)))
+#if defined(ARDUINO_ARCH_ESP32) && defined(RX) && defined(TX)
   constexpr uint8_t hardwareRX = RX;
   constexpr uint8_t hardwareTX = TX;
 `#else`
   // use defaults for RX/TX
   constexpr uint8_t hardwareRX = 3;
   constexpr uint8_t hardwareTX = 1;
 `#endif`
🤖 Fix all issues with AI agents
In `@wled00/wled_boards.h`:
- Around line 130-136: The comment marking RTC memory as "TBC" is misleading
because util.cpp (around util.cpp:701) already uses MALLOC_CAP_RTCRAM for
conditional allocation; update wled_boards.h by removing the "TBC" text and
either (a) leave `#define` WLED_HAVE_RTC_MEMORY_HEAP 1 as a confirmed capability
(matching how ESP32-C61 is documented) or (b) gate the definition behind the
proper IDF config macro (e.g., only define WLED_HAVE_RTC_MEMORY_HEAP when
CONFIG_IDF_TARGET_ESP32P4 or the appropriate ESP-IDF capability macro is
present); ensure the comment style matches other board entries and that
WLED_HAVE_RTC_MEMORY_HEAP is treated consistently with util.cpp usage.
🧹 Nitpick comments (2)
wled00/ota_update.cpp (1)

18-23: Keep bootloader offset single‑sourced.

Now that offsets vary by target, consider wiring the OTA context to BOOTLOADER_OFFSET to prevent future mismatches.

Suggested follow-up
-  const uint32_t bootloaderOffset = 0x1000;
+  const uint32_t bootloaderOffset = BOOTLOADER_OFFSET;
platformio.ini (1)

392-420: Pin the NeoPixelBus C5 fork to a commit hash instead of a branch ref.
Branch pointers can move or be deleted, breaking reproducible builds. Use a commit hash or tag for CI artifacts. This aligns with the pattern used elsewhere in the file (e.g., GifDecoder.git#bc3af189b6b1e06946569f6b4287f0b79a860f8e).

* remove last scan results when changing band mode
* set band mode before starting a new scan
allow max Tx power = 21 dBm if framework supports it.
If not supported, silently clamp to 19.5 dBm.
according to espressif docs, this is "maximum TX power" not "TX power"
coderabbitai[bot]

This comment was marked as resolved.

* shortened another mega-ifdef
* added missing CONFIG_IDF_TARGET_ESP32C61
@wled wled deleted a comment from ianhobbs Feb 11, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
usermods/audioreactive/audio_reactive.cpp (1)

1207-1232: ⚠️ Potential issue | 🔴 Critical

Add ESP32-C6 to hardware capability guards.

Both guards need C6 added:

  • Line 1207: C6 doesn't support PDM microphones
  • Line 1223: C6 doesn't support ADC over I2S (only classic ESP32 does)
Proposed fix
-        `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
+        `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6)
         case 5:
           // ... PDM case
         `#endif`
         // ...
-        `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+        `#if`  !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32S3)
         // ADC over I2S is only possible on "classic" ESP32
         case 0:
wled00/FX_fcn.cpp (1)

1194-1211: ⚠️ Potential issue | 🟠 Major

Fix single‑I2S memory accounting to match bus placement.
When useParallelI2S is false, this still assumes the first digital bus uses I2S (digitalCount == 1). With single‑I2S moved to the last bus, maxI2S can be computed from the wrong bus and under‑estimate DMA size, letting configs slip past the MAX_LED_MEMORY check. If S3 uses a different index, adjust accordingly.

🔧 Proposed fix (align single‑I2S to the last bus)
-    const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1));
+    const bool usesI2S = useParallelI2S
+      ? (digitalCount <= 8)
+      : (digitalCount == 9); // single I2S lives on last bus (digitalCount=9)
@@
-    const bool usesI2S = (useParallelI2S && digitalCount <= 8);
+    const bool usesI2S = useParallelI2S
+      ? (digitalCount <= 8)
+      : (digitalCount == 5); // single I2S lives on last bus (digitalCount=5)

Based on learnings: In WLED PR #5267, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S hardware, not just check digitalCount <= 8.

wled00/wled.h (2)

158-165: ⚠️ Potential issue | 🟡 Minor

Fix DMX guard indentation and clarify the C61 error text.

Indent nested preprocessor directives by two spaces and include C61 in the #error message to match the guard list. As per coding guidelines: Use 2-space indentation for non-generated C++ header files (.h).

🛠️ Proposed fix
 `#ifdef` WLED_ENABLE_DMX
- `#if` defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6)  || defined(CONFIG_IDF_TARGET_ESP32C61)  || defined(CONFIG_IDF_TARGET_ESP32P4) 
-  `#error` "DMX output is not supported on ESP32-C5/C6/P4 (esp_dmx library excluded)"
- `#elif` defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3)|| defined(CONFIG_IDF_TARGET_ESP32S2)
-  `#include` "src/dependencies/dmx/ESPDMX.h"
- `#else` //ESP32
-  `#include` "src/dependencies/dmx/SparkFunDMX.h"
- `#endif`
+  `#if` defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6)  || defined(CONFIG_IDF_TARGET_ESP32C61)  || defined(CONFIG_IDF_TARGET_ESP32P4)
+    `#error` "DMX output is not supported on ESP32-C5/C6/C61/P4 (esp_dmx library excluded)"
+  `#elif` defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3)|| defined(CONFIG_IDF_TARGET_ESP32S2)
+    `#include` "src/dependencies/dmx/ESPDMX.h"
+  `#else` //ESP32
+    `#include` "src/dependencies/dmx/SparkFunDMX.h"
+  `#endif`
 `#endif`
@@
 `#ifdef` WLED_ENABLE_DMX
- `#if` defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6)  || defined(CONFIG_IDF_TARGET_ESP32C61)  || defined(CONFIG_IDF_TARGET_ESP32P4) 
-  `#error` "DMX output is not supported on ESP32-C5/C6/P4 (esp_dmx library excluded)"
- `#elif` defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S2)
-  WLED_GLOBAL DMXESPSerial dmx;
- `#else` //ESP32
-  WLED_GLOBAL SparkFunDMX dmx;
- `#endif`
+  `#if` defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6)  || defined(CONFIG_IDF_TARGET_ESP32C61)  || defined(CONFIG_IDF_TARGET_ESP32P4)
+    `#error` "DMX output is not supported on ESP32-C5/C6/C61/P4 (esp_dmx library excluded)"
+  `#elif` defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S2)
+    WLED_GLOBAL DMXESPSerial dmx;
+  `#else` //ESP32
+    WLED_GLOBAL SparkFunDMX dmx;
+  `#endif`
 `#endif`

Also applies to: 480-487


334-344: ⚠️ Potential issue | 🟠 Major

Fix RX/TX detection: defined() cannot detect C++ constants.

In Arduino-ESP32, RX/TX are defined as C++ constants (static const uint8_t) in pins_arduino.h, not preprocessor macros. The #if defined(RX) check cannot detect them. This causes the condition to always use hardcoded defaults (3, 1) for non-classic ESP32 variants, ignoring their actual UART0 pins (e.g., C3: 20/21, C5: 12/11, C6: 17/16, S2/S3: 44/43). Either use runtime assignment or include the actual Arduino headers to access the constants properly.

🤖 Fix all issues with AI agents
In `@usermods/audioreactive/audio_reactive.cpp`:
- Around line 1800-1803: The analog microphone JSON serialization blocks (e.g.,
the creation of JsonObject amic via top.createNestedObject and assignments of
amic["pin"] and related analog-mic fields) are missing ESP32-C6 in their
exclusion preprocessor guards; update the conditional macros around these
sections (the guard at the block creating amic and the subsequent analog-mic
serialization blocks) to also exclude CONFIG_IDF_TARGET_ESP32C6 (or switch to
the positive CONFIG_IDF_TARGET_ESP32 guard to target classic ESP32 only) so the
analog mic fields are omitted for ESP32S2, ESP32C3, ESP32C5, ESP32S3 and ESP32C6
consistently.

In `@wled00/bus_manager.cpp`:
- Around line 553-560: The TODO comment contains typos and an incorrect target
name; update the comment near the ledc_set_duty_and_update call (and the
surrounding LEDC/LEDC.channel_group comments) to fix spelling ("impemented" ->
"implemented") and correct the target reference ("P5" -> "P4" or "ESP32P4" to
match the `#if` condition). Ensure the TODO clearly references the LEDC struct
behavior and dithering support for ESP32P4 and leaves the rest of the technical
notes unchanged.

In `@wled00/wled.h`:
- Around line 427-429: The extern declaration for the global useParallelI2S in
bus_manager.cpp must be guarded to match its definition in wled.h; wrap the
extern bool useParallelI2S declaration with the same conditional compile guards
used for the definition (i.e., only declare it when building for ESP32 with
WLED_HAS_PARALLEL_I2S) so non-parallel I2S targets do not get an unresolved
extern reference.
🧹 Nitpick comments (2)
usermods/audioreactive/audio_reactive.cpp (1)

1163-1232: Consider centralizing hardware capability guards.

The PR objectives mention wled_boards.h was added to centralize capability flags. Rather than repeating long #if !defined(...) chains throughout this file, consider defining capability macros like:

// In wled_boards.h
`#if` defined(CONFIG_IDF_TARGET_ESP32)
  `#define` WLED_HAS_ANALOG_MIC 1
  `#define` WLED_HAS_PDM_MIC 1
`#elif` defined(CONFIG_IDF_TARGET_ESP32S3)
  `#define` WLED_HAS_PDM_MIC 1
`#endif`

Then guards become simple: #ifdef WLED_HAS_ANALOG_MIC — cleaner, future-proof, and consistent across files.

wled00/ws.cpp (1)

83-96: Optional: name the DDP header length constant.

The two bounds checks use the 10 literal; extracting it avoids magic numbers and keeps the checks in sync.

♻️ Suggested update
 constexpr uint8_t BINARY_PROTOCOL_E131    = P_E131; // = 0, untested!
 constexpr uint8_t BINARY_PROTOCOL_ARTNET  = P_ARTNET; // = 1, untested!
 constexpr uint8_t BINARY_PROTOCOL_DDP     = P_DDP; // = 2
+constexpr size_t  DDP_HEADER_LEN          = 10;    // bytes (excluding protocol byte)

 ...
-            if (len < size_t(10 + offset)) return; // DDP header is 10 bytes (+1 protocol byte)
+            if (len < size_t(DDP_HEADER_LEN + offset)) return; // DDP header is 10 bytes (+1 protocol byte)
 ...
-            if (len < size_t(10 + offset + ddpDataLen)) return; // not enough data, prevent out of bounds read
+            if (len < size_t(DDP_HEADER_LEN + offset + ddpDataLen)) return; // not enough data, prevent out of bounds read

Based on learnings: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit.

these variables are defined in wled.h, which is included already.
@softhack007
Copy link
Member

@coderabbitai please remember for future reviews: check that all global variables in .cpp files are well-defined (via .h file or via "extern"). Verify that declarations are neither duplicated, nor implicitly declared as "int".

@coderabbitai

This comment was marked as resolved.

@softhack007

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
usermods/audioreactive/audio_source.h (1)

25-33: ⚠️ Potential issue | 🟡 Minor

Update the unsupported-target message to match the expanded guard.

The guard now includes ESP32‑C61 (and other targets already in the list), but the message only mentions C2/C3, which is misleading during build failures/warnings.

🔧 Suggested tweak
-  `#error` This audio reactive usermod does not support ESP32-C2 or ESP32-C3.
+  `#error` This audio reactive usermod does not support this target.
...
-  `#warning` This audio reactive usermod does not support ESP32-C2 and ESP32-C3.
+  `#warning` This audio reactive usermod does not support this target.
wled00/data/settings_wifi.htm (1)

72-80: ⚠️ Potential issue | 🟡 Minor

Guard against missing channel values in scan results.

Some scans omit channel, which would render “Ch undefined” in the UI.

🛠️ Suggested adjustment
-							option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm, Ch ${networks[i].channel})`; // [${networks[i].bssid.replaceAll(':','')}]
+							const ch = Number.isFinite(networks[i].channel) ? `, Ch ${networks[i].channel}` : "";
+							option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm${ch})`; // [${networks[i].bssid.replaceAll(':','')}]
wled00/FX_fcn.cpp (1)

1163-1184: ⚠️ Potential issue | 🟠 Major

Fix I2S DMA buffer estimation for single‑I2S mode.

When useParallelI2S is false, usesI2S only triggers on the first digital bus. The current bus allocation places single‑I2S on the last digital bus, so maxI2S can be underestimated and the MAX_LED_MEMORY check can pass when it shouldn’t. Track the total digital bus count and use that to detect the last bus.

🐛 Suggested fix
-  digitalCount = 0;
+  const unsigned totalDigitalBuses = digitalCount;
+  digitalCount = 0;
-    const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1));
+    const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == totalDigitalBuses));
-    const bool usesI2S = (useParallelI2S && digitalCount <= 8);
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == totalDigitalBuses);

Based on learnings: In WLED, both parallel I2S and single I2S modes require additional DMA buffers (4× the pixel buffer size). The memory calculation must account for which specific buses use I2S hardware, not just check digitalCount <= 8, because single I2S mode places the I2S bus at the END (ESP32 bus 8 with digitalCount=9, S2 bus 4 with digitalCount=5).

Also applies to: 1194-1209

🤖 Fix all issues with AI agents
In `@wled00/data/settings_wifi.htm`:
- Around line 253-258: You changed the WiFi UI (wled00/data/settings_wifi.htm —
elements with id "bm" and "tx"), so regenerate the embedded UI headers by
running the project's UI build step (npm run build) to update the generated
headers used in firmware builds; after running the build verify the generated
header files changed and include them in the PR so the firmware build stays in
sync with settings_wifi.htm.
🧹 Nitpick comments (2)
wled00/bus_wrapper.h (1)

509-513: Track the TODO to simplify the long guard.
Happy to help refactor this into a helper macro or wrapper if you want to tackle it now.

wled00/ota_update.cpp (1)

18-23: Bootloader offsets and ESP32-C5 chip ID verified as correct.

The values for ESP32-C5 (chip_id 0x0017, bootloader offset 0x2000) and ESP32-C61 (bootloader offset 0x0000) match ESP-IDF documentation. Bootloader offsets are already properly hoisted into the BOOTLOADER_OFFSET constant.

Optional: Consider defining chip ID constants. The chip IDs are currently hardcoded in the validation checks (lines 415–450), though they are documented in comments (lines 405–413). Replacing hardcoded values like 0x0017 with named constants (e.g., ESP32C5_CHIP_ID = 0x0017) would improve maintainability and reduce drift risk if ESP-IDF updates these values.

@softhack007
Copy link
Member

softhack007 commented Feb 12, 2026

@coderabbitai - related to #5048 (comment)

a) please compare the "LEDC CAPS" sections in esp-df 5.5.2 "soc_caps.h". Are there differences that must be considered when re-writing our analog LEDs (ledc pwm) support code? Also check for related differences in "SOC_*_SUPPORTED" flags.

b) Some commits in esp-idf are related to the "duty" field - it looks some chips don't support the feature

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Fetch LEDC capabilities from each ESP32 variant's soc_caps.h in ESP-IDF 5.5.2

echo "=== ESP32 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

echo -e "\n=== ESP32-S2 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32s2/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

echo -e "\n=== ESP32-S3 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32s3/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

echo -e "\n=== ESP32-C3 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32c3/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

echo -e "\n=== ESP32-C5 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32c5/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

echo -e "\n=== ESP32-C6 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32c6/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

echo -e "\n=== ESP32-P4 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/esp32p4/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -40

Length of output: 3433


🏁 Script executed:

#!/bin/bash

# Also check for SOC_LEDC_SUPPORTED flags across all chips

echo "=== Checking SOC_LEDC_SUPPORTED across all chips ==="

for chip in esp32 esp32s2 esp32s3 esp32c3 esp32c5 esp32c6 esp32p4; do
  echo "--- $chip ---"
  curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/30aaf64524299d3bde422ca9a2848090d1bc5d0f/components/soc/$chip/include/soc/soc_caps.h" | grep -E "SOC_LEDC_SUPPORTED|SOC_.*PWM"
done

Length of output: 7821


@softhack007: Analyzed LEDC capabilities across all ESP32 variants in ESP-IDF 5.5.2. Here are the critical differences for the analog LED PWM rewrite:


🚨 Breaking Differences Requiring Conditional Code

1️⃣ Channel Count (affects max analog LEDs)

Chip Channels Change
ESP32, S2, S3, P4 8 Full capacity
C3, C5, C6 6 ⚠️ 25% reduction

Impact: WLED_MAX_ANALOG_CHANNELS must be conditional on chip.


2️⃣ Timer Bit Width (duty resolution)

Chip Bit Width Max Duty
ESP32 20-bit 1,048,576 levels
S2, S3, C3 14-bit 16,384 levels
C5, C6, P4 20-bit 1,048,576 levels

Impact: Duty calculations need SOC_LEDC_TIMER_BIT_WIDTH macro or runtime detection.


3️⃣ Clock Sources (critical API change!)

Chip Clock Sources Notes
ESP32 APB, REF_TICK Has HS_MODE
S2 APB, REF_TICK, XTAL Timer-specific mux
S3, C3 APB, XTAL No REF_TICK
C5, C6, P4 PLL_DIV, XTAL ⚠️ No APB clock!

Breaking: Code using LEDC_APB_CLK won't compile for C5/C6/P4. Must use:

  • LEDC_USE_PLL_DIV_CLK for C5/C6/P4
  • LEDC_USE_APB_CLK for older chips

4️⃣ High-Speed Mode

  • Only ESP32 classic has SOC_LEDC_SUPPORT_HS_MODE (1)
  • All others: LS mode only
  • Must guard LEDC_HIGH_SPEED_MODE references with #ifdef SOC_LEDC_SUPPORT_HS_MODE

5️⃣ New Features (C5/C6/P4 only)

SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED (1)      // Hardware gamma correction
SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX (16)     // 16-step gamma curves
SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10)          // 10-bit fade params
SOC_LEDC_SUPPORT_SLEEP_RETENTION (1)         // Preserve state in sleep

Opportunity: Could leverage hardware gamma on C5/C6/P4 for smoother fades.


6️⃣ Fade Stop Support

  • ESP32 classic: ❌ No SOC_LEDC_SUPPORT_FADE_STOP
  • All others: ✅ Support fade stop

Impact: ledc_fade_stop() API not available on classic ESP32.


📋 Recommended Conditional Compilation Strategy

// In bus_manager.cpp or BusPwm class:

// 1. Channel count
`#if` SOC_LEDC_CHANNEL_NUM == 6
  `#define` WLED_MAX_ANALOG_CHANNELS 6  // C3/C5/C6
`#else`
  `#define` WLED_MAX_ANALOG_CHANNELS 8  // ESP32/S2/S3/P4
`#endif`

// 2. Clock source selection
`#ifdef` SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
  ledc_timer.clk_cfg = LEDC_USE_PLL_DIV_CLK;  // C5/C6/P4
`#else`
  ledc_timer.clk_cfg = LEDC_USE_APB_CLK;      // ESP32/S2/S3/C3
`#endif`

// 3. Speed mode
`#ifdef` SOC_LEDC_SUPPORT_HS_MODE
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;  // Only ESP32 classic
`#else`
  ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;   // All others
`#endif`

// 4. Duty resolution (use SOC macro directly)
ledc_timer.duty_resolution = SOC_LEDC_TIMER_BIT_WIDTH;

// 5. Fade stop (if using fade API)
`#ifdef` SOC_LEDC_SUPPORT_FADE_STOP
  ledc_fade_stop(LEDC_LOW_SPEED_MODE, channel);
`#endif`

⚠️ Additional Notes

  • MCPWM availability: ESP32/S3/C5/C6/P4 have MCPWM (alternative PWM peripheral), but S2/C3 do not.
  • Timer-specific mux: Only ESP32 and S2 have SOC_LEDC_HAS_TIMER_SPECIFIC_MUX — likely not relevant for basic PWM.
  • All chips support SOC_LEDC_SUPPORTED — no need to gate LEDC usage entirely.

🎯 Priority Actions

  1. Replace hardcoded clock source (LEDC_APB_CLK → conditional based on SOC_LEDC_SUPPORT_PLL_DIV_CLOCK)
  2. Guard HS mode references (only valid for classic ESP32)
  3. Use SOC_LEDC_CHANNEL_NUM macro instead of assuming 8 channels
  4. Use SOC_LEDC_TIMER_BIT_WIDTH for duty calculations
  5. Consider hardware gamma feature on C5/C6/P4 for future optimization

This should cover all breaking changes for the IDF V5 LEDC rewrite! 🚀


🧠 Learnings used
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR `#5134`, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR `#4798`, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/bus_manager.cpp:549-556
Timestamp: 2026-02-11T16:19:58.009Z
Learning: ESP-IDF V5 requires a complete rewrite of the LEDC (PWM/analog LED) subsystem in WLED. The framework now manages LEDC channels internally (unlike V4 where WLED managed them directly), and dithering functionality may not work as it did before. Direct LEDC struct access (e.g., `LEDC.channel_group[gr].channel[ch].duty.duty`) used in the current implementation will need to be replaced with proper HAL API calls. This affects `wled00/bus_manager.cpp` BusPwm class and related pin manager LEDC allocation code.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1176-1187
Timestamp: 2025-09-16T18:08:42.848Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/wled.cpp:385-387
Timestamp: 2026-02-08T19:32:56.086Z
Learning: In WLED ESP32 code, when checking whether USB CDC serial initialization delay is needed, rely on the ARDUINO_USB_CDC_ON_BOOT flag rather than explicit CONFIG_IDF_TARGET checks, because not all development boards for chips with native USB capability (ESP32-C3/C5/C6/S2/S3/H2/P4) actually use the native USB—many have external UART bridge chips instead. The ARDUINO_USB_CDC_ON_BOOT flag correctly indicates the board's actual USB configuration.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-28T14:06:48.772Z
Learning: In WLED post-commit ee9ac947, the rendering pipeline uses per-segment buffers and per-pixel bus updates. Unmapped (0xFFFF) mapping entries are now skipped in WS2812FX::show() (no “clear to black”), which can leave physical gap LEDs with stale/random colors unless they are explicitly cleared. This is a behavior change from pre-0.16 where a full physical buffer was effectively refreshed each frame.

Learnt from: softhack007
Repo: wled/WLED PR: 5107
File: boards/adafruit_matrixportal_esp32s3.json:1-66
Timestamp: 2025-11-22T20:33:14.840Z
Learning: In WLED, board JSON files in the boards/ directory may reference partition files that don't exist or have slightly different names than actual files in tools/. This is intentional because platformio.ini or platformio_override.sample.ini explicitly override the partition file using the board_build.partitions setting, which takes precedence over the board JSON partition reference. This pattern exists in multiple local board definitions and should not be flagged as an issue.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T11:14:24.380Z
Learning: In WLED code reviews, verify that all global variables in .cpp files are properly declared: check that they are defined via .h file or via "extern" declaration, verify that declarations are not duplicated, and ensure they are not implicitly declared as "int" (which can happen when the type is omitted).

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T17:17:04.646Z
Learning: In WLED code reviews, when C-style functions or variables are added or modified, check if they are globally visible (not static). If the function/variable is not declared in any global header file (like fcn_declare.h), suggest either: (1) making it static (visible only within the translation unit) with a forward declaration if needed, or (2) adding a comment to clarify that the function/variable is intentionally global. This helps reduce global namespace pollution and enables better compiler optimizations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-13T21:23:35.514Z
Learning: In WLED, the global `paletteBlend` variable (wled.h:603) and the `WS2812FX::paletteBlend` member (FX.h:940) are duplicates without synchronization code. The global is loaded/saved in cfg.cpp and set via UI in set.cpp, but never copied to the strip member. This is the only such case in the codebase; other settings are either strip-only members (autoSegments, correctWB, cctFromRgb, isMatrix) or global-only (gammaCorrectCol/Bri/Val, blendingStyle).

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T14:38:09.949Z
Learning: In WLED code reviews, check that FastLED noise function aliases (`inoise8`, `inoise16`, etc.) are not used. These should be replaced with the proper WLED functions (`perlin8`, `perlin16`, etc.) as the `inoise*` functions are only aliases kept for compatibility reasons.

Learnt from: softhack007
Repo: wled/WLED PR: 5355
File: wled00/util.cpp:635-638
Timestamp: 2026-02-07T16:06:14.651Z
Learning: ESP32-C61, ESP32-C5, and ESP32-P4 all support external PSRAM. Only ESP32-C3, ESP32-C6, and ESP8266 do not support PSRAM and should be excluded from PSRAM-related compilation guards in WLED.

Learnt from: willmmiles
Repo: wled/WLED PR: 4890
File: lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S:8-16
Timestamp: 2025-09-02T02:27:39.220Z
Learning: The ESP32 macro is defined when compiling code on all ESP32 variants (ESP32, ESP32-S2, ESP32-S3, ESP32-C3, etc.) in the Arduino framework, providing consistent library compatibility across the entire ESP32 family. For target-specific detection, CONFIG_IDF_TARGET_* macros should be used instead.

Learnt from: blazoncek
Repo: wled/WLED PR: 4482
File: wled00/udp.cpp:147-149
Timestamp: 2025-02-19T12:43:34.199Z
Learning: ESP8266 and ESP32 platforms have different maximum segment name lengths in WLED, which can cause truncation when syncing segment names between devices. This platform difference affects the user experience when using the segment name sync feature.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED PR `#5267`, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S in single mode, not just check digitalCount <= 8.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/wled_eeprom.cpp:0-0
Timestamp: 2025-09-01T10:26:17.959Z
Learning: In WLED PR `#4876`, the DMXStartLED EEPROM backward compatibility issue was partially addressed by keeping it at address 2550 and reading it as a 16-bit value, with DMXChannelsValue array moved to addresses 2552-2566. This maintains compatibility with pre-0.11 EEPROM layouts for DMXStartLED, though legacy "Set to 255" (code 6) configurations may still need migration logic.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
wled00/dmx_output.cpp (1)

71-76: ⚠️ Potential issue | 🟡 Minor

Fix indentation of the preprocessor block in initDMXOutput().

The #if/#else/#endif lines are indented by one space; this file requires 2-space indentation.

🔧 Proposed fix
 void initDMXOutput() {
- `#if` defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32S2)
+  `#if` defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) || defined(CONFIG_IDF_TARGET_ESP32S2)
   dmx.init(512);        // initialize with bus length
- `#else`
+  `#else`
   dmx.initWrite(512);  // initialize with bus length
- `#endif`
+  `#endif`
 }

As per coding guidelines: wled00/**/*.cpp: Use 2-space indentation for C++ source files (.cpp).

usermods/audioreactive/audio_source.h (1)

25-33: ⚠️ Potential issue | 🟡 Minor

Align the warning text with the expanded target guard.

The guard now includes C5/C6/C61/H2, but the warning/error still says only C2/C3, which is confusing for builders on the newly added targets.

💬 Suggested wording update
-  `#error` This audio reactive usermod does not support ESP32-C2 or ESP32-C3.
+  `#error` This audio reactive usermod is not supported on this MCU (C2/C3/C5/C6/C61/H2).
...
-  `#warning` This audio reactive usermod does not support ESP32-C2 and ESP32-C3.
+  `#warning` This audio reactive usermod is not supported on this MCU (C2/C3/C5/C6/C61/H2).
wled00/FX_fcn.cpp (1)

1194-1211: ⚠️ Potential issue | 🟠 Major

Fix I2S memory estimation for single‑I2S bus placement.

usesI2S still assumes the single‑I2S bus is the first digital bus (digitalCount == 1). The bus allocation strategy now places single‑I2S on the last bus (ESP32 bus 8, ESP32‑S2 bus 4), so the I2S DMA memory estimate can be skipped entirely and undercount maxI2S.

🔧 Example adjustment
-#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
-    const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1));
-#elif defined(CONFIG_IDF_TARGET_ESP32S2)
-    const bool usesI2S = (useParallelI2S && digitalCount <= 8);
+#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) ||
+                         (!useParallelI2S && digitalCount == 9);
+#elif defined(CONFIG_IDF_TARGET_ESP32S2)
+    const bool usesI2S = (useParallelI2S && digitalCount <= 8) ||
+                         (!useParallelI2S && digitalCount == 5);

Based on learnings, “single I2S” now uses the last bus (ESP32 bus 8 / S2 bus 4), so memory accounting must key off that bus index instead of digitalCount == 1.

wled00/wled.h (1)

334-344: ⚠️ Potential issue | 🔴 Critical

Guard RX/TX usage on boards that don't define those macros.

The current logic silently uses RX=3 and TX=1 for any non-classic ESP32 variant that doesn't define those macros. However, non-classic ESP32 variants (ESP32-C3, ESP32-C5, ESP32-C6, etc.) have different UART0 pins—falling back to 3/1 for those variants is incorrect. For example, ESP32-C3 UART0 defaults to GPIO20/21, not GPIO3/1.

The fix should guard RX/TX usage explicitly and only provide the 3/1 fallback for classic ESP32. Add an error directive for variants without RX/TX defined to prevent silent pin misconfigurations.

🔧 Proposed hardening
-#if defined(ARDUINO_ARCH_ESP32) && (!defined(CONFIG_IDF_TARGET_ESP32) || (defined(RX) && defined(TX)))
-  // use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1
-  constexpr uint8_t hardwareRX = RX;
-  constexpr uint8_t hardwareTX = TX;
-#else
-  // use defaults for RX/TX
-  constexpr uint8_t hardwareRX = 3;
-  constexpr uint8_t hardwareTX = 1;
-#endif
+#if defined(ARDUINO_ARCH_ESP32) && defined(RX) && defined(TX)
+  // use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1
+  constexpr uint8_t hardwareRX = RX;
+  constexpr uint8_t hardwareTX = TX;
+#elif defined(CONFIG_IDF_TARGET_ESP32)
+  // use defaults for RX/TX on classic ESP32
+  constexpr uint8_t hardwareRX = 3;
+  constexpr uint8_t hardwareTX = 1;
+#else
+  `#error` "RX/TX are not defined for this ESP32 variant. Please define RX/TX (or provide a board-specific default)."
+#endif
🧹 Nitpick comments (4)
wled00/ws.cpp (1)

86-99: Replace the DDP header magic number and align types.

10 is a protocol constant; making it a named constexpr improves readability and avoids repeating magic numbers. While you’re here, consider making offset a size_t to avoid mixed signed/unsigned arithmetic.

♻️ Suggested tweak
-        constexpr int offset = 1; // offset to skip protocol byte
+        constexpr size_t offset = 1; // offset to skip protocol byte
+        constexpr size_t DDP_HEADER_LEN = 10;
         switch (data[0]) {
@@
-            if (len < size_t(10 + offset)) return; // DDP header is 10 bytes (+1 protocol byte)
+            if (len < DDP_HEADER_LEN + offset) return; // DDP header is 10 bytes (+1 protocol byte)
             size_t ddpDataLen = (data[8+offset] << 8) | data[9+offset]; // data length in bytes from DDP header
@@
-            if (len < size_t(10 + offset + ddpDataLen)) return; // not enough data, prevent out of bounds read
+            if (len < DDP_HEADER_LEN + offset + ddpDataLen) return; // not enough data, prevent out of bounds read

Based on learnings: "In WLED code reviews, when code is modified or added, look for 'magic numbers' (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when meaningful constants exist in the codebase."

wled00/udp.cpp (1)

723-743: Consider using WLED_BOARD to avoid the growing #elif chain.

Now that wled_boards.h provides a canonical WLED_BOARD, this can be simplified and kept in sync automatically.

♻️ Possible refactor
-#ifdef ESP8266
-  data[38] = NODE_TYPE_ID_ESP8266;
-#elif defined(CONFIG_IDF_TARGET_ESP32C5)
-  data[38] = NODE_TYPE_ID_ESP32C5;
-#elif defined(CONFIG_IDF_TARGET_ESP32C6)
-  data[38] = NODE_TYPE_ID_ESP32C6;
-#elif defined(CONFIG_IDF_TARGET_ESP32C61)
-  data[38] = NODE_TYPE_ID_ESP32C61;
-#elif defined(CONFIG_IDF_TARGET_ESP32C3)
-  data[38] = NODE_TYPE_ID_ESP32C3;
-#elif defined(CONFIG_IDF_TARGET_ESP32S3)
-  data[38] = NODE_TYPE_ID_ESP32S3;
-#elif defined(CONFIG_IDF_TARGET_ESP32S2)
-  data[38] = NODE_TYPE_ID_ESP32S2;
-#elif defined(CONFIG_IDF_TARGET_ESP32P4)
-  data[38] = NODE_TYPE_ID_ESP32P4;
-#elif defined(ARDUINO_ARCH_ESP32)
-  data[38] = NODE_TYPE_ID_ESP32;
-#else
-  data[38] = NODE_TYPE_ID_UNDEFINED;
-#endif
+  data[38] = WLED_BOARD;
wled00/FXparticleSystem.cpp (1)

502-510: Update fast-divide comments to match the capability flag.

The guard is now macro-driven, but the inline comments still name specific targets. Consider making the comment macro-based to avoid drift.

✏️ Suggested comment tweak (apply to each affected block)
-  `#else` // division is faster on ESP32, S2 and S3
+  `#else` // division is faster when WLED_HAVE_FAST_int_DIVIDE is set

Also applies to: 516-528, 931-937, 959-969, 1412-1424, 1705-1709, 1726-1732

wled00/wled.cpp (1)

989-996: Consider adding IDF version guard for WiFi.getBand() for consistency.

The guard #if defined(ARDUINO_ARCH_ESP32) && SOC_WIFI_SUPPORT_5G differs from the guards used for WiFi.setBandMode() at lines 537 and 748, which also check ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2). While in practice SOC_WIFI_SUPPORT_5G currently implies IDF 5.4+ (since ESP32-C5 is the only chip defining it), adding the version check would maintain consistency and future-proof the code.

♻️ Optional: Add version guard for consistency
-    `#if` defined(ARDUINO_ARCH_ESP32) && SOC_WIFI_SUPPORT_5G
+    `#if` defined(ARDUINO_ARCH_ESP32) && defined(SOC_WIFI_SUPPORT_5G) && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2))
       auto wifiBand = WiFi.getBand();
       DEBUG_PRINT(wifiBand == WIFI_BAND_2G ? F(" (2.4GHz)") : (wifiBand == WIFI_BAND_5G ? F("  (5GHz)"): F(" (other)")));
     `#else`

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@softhack007: I previously provided a comprehensive LEDC capabilities analysis in this comment, but let me fetch the latest data directly from the ESP-IDF 5.5.2 sources you linked to verify completeness and check those duty field commits.


🌐 Web query:

ESP-IDF 5.5.2 esp32 soc_caps.h LEDC capabilities SOC_LEDC

💡 Result:

In ESP-IDF v5.5.2, the LEDC (LED PWM) feature flags and limits are exposed via SoC capability macros in:

  • components/soc/<target>/include/soc/soc_caps.h (include with #include "soc/soc_caps.h") [1]

Common “is LEDC present?” macro

  • SOC_LEDC_SUPPORTED [1]

ESP32 (classic) LEDC capability macros (examples)

On ESP32, soc_caps.h defines (among others) these LEDC-related macros [1]:

  • SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
  • SOC_LEDC_SUPPORT_APB_CLOCK
  • SOC_LEDC_SUPPORT_REF_TICK
  • SOC_LEDC_SUPPORT_HS_MODE
  • SOC_LEDC_TIMER_NUM
  • SOC_LEDC_CHANNEL_NUM
  • SOC_LEDC_TIMER_BIT_WIDTH

Newer targets may expose different/additional LEDC macros (example: ESP32-C5)

On ESP32-C5, the LEDC capability set includes (among others) [2]:

  • SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
  • SOC_LEDC_SUPPORT_XTAL_CLOCK
  • SOC_LEDC_TIMER_NUM, SOC_LEDC_CHANNEL_NUM, SOC_LEDC_TIMER_BIT_WIDTH
  • SOC_LEDC_SUPPORT_FADE_STOP
  • SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED, SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX
  • SOC_LEDC_FADE_PARAMS_BIT_WIDTH
  • SOC_LEDC_SUPPORT_SLEEP_RETENTION

If you tell me your exact target (esp32 / esp32s2 / esp32s3 / esp32c3 / esp32c6 / esp32h2 / esp32c5, etc.), I can list the exact SOC_LEDC_* macros and their values for that chip.

Sources: ESP-IDF Programming Guide (v5.5.2) SoC capabilities pages for ESP32 and ESP32-C5 [1][2].


🌐 Web query:

ESP-IDF commit fbdb9413def5840df465a554bd7899aef74e3b6b ESP32-P4 LEDC duty field changes

💡 Result:

In ESP-IDF commit fbdb9413def5840df465a554bd7899aef74e3b6b (“feat(ledc): ESP32P4 ECO5 LEDC related updates”), the ESP32-P4 LEDC readback duty register field name was changed in the SoC register struct, and the HAL/LL accessor was updated accordingly:

  • Register struct bitfield rename (ESP32-P4 ledc_struct.h, hw_ver1):

    • The RO register description changed from duty_ch0_r to duty_r.
    • The 25-bit bitfield inside that union changed from duty to duty_r (still [24:0]). This is a C struct field-name change, not a width/position change. [1]
  • LEDC LL API update (ledc_ll_get_duty):

    • Readback switched from:
      • ...channel[channel_num].duty_r.duty >> 4
    • to:
      • ...channel[channel_num].duty_r.duty_r >> 4 [1]

Practical impact: any code (especially low-level/LL code) that directly referenced ...duty_r.duty on ESP32-P4 must be updated to ...duty_r.duty_r after this commit. [1]

Sources:
[1] ESP-IDF commit fbdb9413def5840df465a554bd7899aef74e3b6b (diff for components/hal/esp32p4/include/hal/ledc_ll.h and components/soc/esp32p4/register/hw_ver1/soc/ledc_struct.h). (github.com)

Citations:


🌐 Web query:

ESP-IDF commit 33fa42ca748614377c1b34c48e5b0a9481b70bf4 ESP32-C5 LEDC duty changes

💡 Result:

ESP-IDF commit 33fa42ca748614377c1b34c48e5b0a9481b70bf4 (“feat(ledc): support ledc on esp32c5”, dated May 15, 2024) adds the LEDC HAL/SoC support for ESP32-C5 and updates the LEDC documentation accordingly. [1]

What changed for “LEDC duty” (relevant to ESP32-C5)

  • Duty range is inclusive of the top value: for ESP32-C5 (and in current ESP-IDF docs), the duty you pass is expected to be:
    • 0 .. (2 ** duty_resolution) (inclusive)
    • Example: duty_resolution = 10 → valid duty values 0..1024. [2][3]
  • This matches the ESP32-C5 LEDC docs (“range … from 0 to (2 ** duty_resolution)”). [3]
  • In older ESP-IDF docs (example: v5.1-rc1), the duty range was documented as:
    • 0 .. (2 ** duty_resolution) - 1 (example 0..1023 for 10-bit). [4]

Practical impact

  • If you have code (or assumptions) written around the older “-1” maximum, on ESP32-C5 you can (and per docs, should) treat (1 << duty_resolution) as the valid “100%” endpoint (e.g. 1024 for 10-bit). [3]

Sources: commit page and diff context [1][2], ESP-IDF LEDC docs (latest / ESP32-C5) [3][4].


🏁 Script executed:

#!/bin/bash

# Fetch LEDC CAPS sections from all ESP32 variants in ESP-IDF 5.5.2
COMMIT="30aaf64524299d3bde422ca9a2848090d1bc5d0f"

echo "=== ESP32 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

echo -e "\n=== ESP32-S2 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32s2/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

echo -e "\n=== ESP32-S3 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32s3/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

echo -e "\n=== ESP32-C3 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32c3/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

echo -e "\n=== ESP32-C5 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32c5/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

echo -e "\n=== ESP32-C6 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32c6/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

echo -e "\n=== ESP32-P4 LEDC CAPS ==="
curl -sL "https://raw.githubusercontent.com/espressif/esp-idf/$COMMIT/components/soc/esp32p4/include/soc/soc_caps.h" | sed -n '/LEDC CAPS/,/^$/p' | head -50

Length of output: 3433


@softhack007: Excellent catch on those duty field commits! Here's the complete LEDC comparison from ESP-IDF 5.5.2 soc_caps.h:

📊 LEDC Capabilities Comparison Table

Capability ESP32 S2 S3 C3 C5 C6 P4
SOC_LEDC_CHANNEL_NUM 8 8 8 6 6 6 8
SOC_LEDC_TIMER_BIT_WIDTH 20 14 14 14 20 20 20
Clock: APB
Clock: PLL_DIV
Clock: XTAL
Clock: REF_TICK
SOC_LEDC_SUPPORT_HS_MODE
SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
SOC_LEDC_SUPPORT_FADE_STOP
SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX 16 16 16
SOC_LEDC_FADE_PARAMS_BIT_WIDTH 10 10 10
SOC_LEDC_SUPPORT_SLEEP_RETENTION

🚨 Critical Breaking Changes for WLED

1️⃣ Clock Source API (BREAKING)

// ❌ OLD CODE (won't compile on C5/C6/P4):
ledc_timer.clk_cfg = LEDC_USE_APB_CLK;

// ✅ NEW CODE:
`#ifdef` SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
  ledc_timer.clk_cfg = LEDC_USE_PLL_DIV_CLK;  // C5/C6/P4
`#else`
  ledc_timer.clk_cfg = LEDC_USE_APB_CLK;      // ESP32/S2/S3/C3
`#endif`

2️⃣ Duty Field Access (C5/P4 specific)

ESP32-P4 (commit fbdb9413):

// ❌ OLD: duty_r.duty
uint32_t duty = LEDC.channel_group[gr].channel[ch].duty_r.duty;

// ✅ NEW on P4: duty_r.duty_r
uint32_t duty = LEDC.channel_group[gr].channel[ch].duty_r.duty_r;

ESP32-C5 (commit 33fa42ca):

  • Duty range changed from 0..(2^resolution - 1) to 0..(2^resolution) inclusive
  • Example: 10-bit duty now accepts 0..1024 (not 0..1023)

3️⃣ Channel Count

// Use SOC macro instead of hardcoded 8:
`#define` WLED_MAX_ANALOG_CHANNELS SOC_LEDC_CHANNEL_NUM  // 6 on C3/C5/C6, 8 on others

4️⃣ High-Speed Mode

`#ifdef` SOC_LEDC_SUPPORT_HS_MODE
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;  // Only ESP32 classic
`#else`
  ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;   // All others
`#endif`

💡 Recommended Code Pattern for bus_manager.cpp

// 1. Clock source selection
`#ifdef` SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
  ledc_timer_config_t timer_conf = {
    .speed_mode = LEDC_LOW_SPEED_MODE,
    .duty_resolution = SOC_LEDC_TIMER_BIT_WIDTH,  // Use SOC macro
    .timer_num = LEDC_TIMER_0,
    .freq_hz = 5000,
    .clk_cfg = LEDC_USE_PLL_DIV_CLK  // C5/C6/P4
  };
`#else`
  ledc_timer_config_t timer_conf = {
    .speed_mode = LEDC_LOW_SPEED_MODE,
    .duty_resolution = SOC_LEDC_TIMER_BIT_WIDTH,
    .timer_num = LEDC_TIMER_0,
    .freq_hz = 5000,
    .clk_cfg = LEDC_USE_APB_CLK      // ESP32/S2/S3/C3
  };
`#endif`

// 2. Duty calculation (account for C5 inclusive range)
uint32_t max_duty = (1 << SOC_LEDC_TIMER_BIT_WIDTH);  // Now inclusive on C5!
uint32_t duty = (brightness * max_duty) / 255;

// 3. Set duty using HAL API (avoid direct struct access on IDF V5)
ledc_set_duty(LEDC_LOW_SPEED_MODE, channel, duty);
ledc_update_duty(LEDC_LOW_SPEED_MODE, channel);

// 4. Optional: leverage hardware gamma on C5/C6/P4
`#ifdef` SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
  // Could use ledc_set_duty_with_gamma() for smoother fades
`#endif`

🎯 Summary of Must-Fix Issues

Issue Affected Chips Fix
No APB clock C5, C6, P4 Use LEDC_USE_PLL_DIV_CLK
Only 6 channels C3, C5, C6 Use SOC_LEDC_CHANNEL_NUM macro
duty_r field rename P4 Access duty_r.duty_r instead of duty_r.duty
Duty range inclusive C5 Max duty is now 2^resolution, not -1
HS mode removed S2, S3, C3, C5, C6, P4 Guard with SOC_LEDC_SUPPORT_HS_MODE

All of these are compile/runtime blockers that must be addressed for C5/C6/P4 support. The good news: all can be handled with conditional compilation using SOC_* macros! 🚀


🧠 Learnings used
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR `#5134`, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR `#4798`, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/bus_manager.cpp:549-556
Timestamp: 2026-02-11T16:19:58.009Z
Learning: ESP-IDF V5 requires a complete rewrite of the LEDC (PWM/analog LED) subsystem in WLED. The framework now manages LEDC channels internally (unlike V4 where WLED managed them directly), and dithering functionality may not work as it did before. Direct LEDC struct access (e.g., `LEDC.channel_group[gr].channel[ch].duty.duty`) used in the current implementation will need to be replaced with proper HAL API calls. This affects `wled00/bus_manager.cpp` BusPwm class and related pin manager LEDC allocation code.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1176-1187
Timestamp: 2025-09-16T18:08:42.848Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5293
File: usermods/user_fx/user_fx.cpp:167-171
Timestamp: 2026-01-13T03:07:20.560Z
Learning: In WLED effects (usermods/user_fx/user_fx.cpp and similar), when storing future timestamps, assignments like `stored_time = now + delay` are correct and handle uint32_t wraparound properly. Only comparison statements need to use subtraction-based elapsed-time checks (e.g., `(now - stored_time) >= delay`). Do not flag assignment statements as needing fixes for wraparound handling.

Learnt from: softhack007
Repo: wled/WLED PR: 5048
File: wled00/wled.cpp:385-387
Timestamp: 2026-02-08T19:32:56.086Z
Learning: In WLED ESP32 code, when checking whether USB CDC serial initialization delay is needed, rely on the ARDUINO_USB_CDC_ON_BOOT flag rather than explicit CONFIG_IDF_TARGET checks, because not all development boards for chips with native USB capability (ESP32-C3/C5/C6/S2/S3/H2/P4) actually use the native USB—many have external UART bridge chips instead. The ARDUINO_USB_CDC_ON_BOOT flag correctly indicates the board's actual USB configuration.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-12-28T14:06:48.772Z
Learning: In WLED post-commit ee9ac947, the rendering pipeline uses per-segment buffers and per-pixel bus updates. Unmapped (0xFFFF) mapping entries are now skipped in WS2812FX::show() (no “clear to black”), which can leave physical gap LEDs with stale/random colors unless they are explicitly cleared. This is a behavior change from pre-0.16 where a full physical buffer was effectively refreshed each frame.

Learnt from: softhack007
Repo: wled/WLED PR: 5107
File: boards/adafruit_matrixportal_esp32s3.json:1-66
Timestamp: 2025-11-22T20:33:14.840Z
Learning: In WLED, board JSON files in the boards/ directory may reference partition files that don't exist or have slightly different names than actual files in tools/. This is intentional because platformio.ini or platformio_override.sample.ini explicitly override the partition file using the board_build.partitions setting, which takes precedence over the board JSON partition reference. This pattern exists in multiple local board definitions and should not be flagged as an issue.

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T11:14:24.380Z
Learning: In WLED code reviews, verify that all global variables in .cpp files are properly declared: check that they are defined via .h file or via "extern" declaration, verify that declarations are not duplicated, and ensure they are not implicitly declared as "int" (which can happen when the type is omitted).

Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-02-11T17:17:04.646Z
Learning: In WLED code reviews, when C-style functions or variables are added or modified, check if they are globally visible (not static). If the function/variable is not declared in any global header file (like fcn_declare.h), suggest either: (1) making it static (visible only within the translation unit) with a forward declaration if needed, or (2) adding a comment to clarify that the function/variable is intentionally global. This helps reduce global namespace pollution and enables better compiler optimizations.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T14:38:09.949Z
Learning: In WLED code reviews, check that FastLED noise function aliases (`inoise8`, `inoise16`, etc.) are not used. These should be replaced with the proper WLED functions (`perlin8`, `perlin16`, etc.) as the `inoise*` functions are only aliases kept for compatibility reasons.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-13T21:23:35.514Z
Learning: In WLED, the global `paletteBlend` variable (wled.h:603) and the `WS2812FX::paletteBlend` member (FX.h:940) are duplicates without synchronization code. The global is loaded/saved in cfg.cpp and set via UI in set.cpp, but never copied to the strip member. This is the only such case in the codebase; other settings are either strip-only members (autoSegments, correctWB, cctFromRgb, isMatrix) or global-only (gammaCorrectCol/Bri/Val, blendingStyle).

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED PR `#5267`, the bus allocation strategy for single I2S mode was changed: ESP32 now uses single I2S on bus 8 (the last bus, digitalCount=9) instead of bus 0; ESP32-S2 uses single I2S on bus 4 (digitalCount=5). Memory calculation logic must account for which specific bus uses I2S in single mode, not just check digitalCount <= 8.

Learnt from: softhack007
Repo: wled/WLED PR: 5355
File: wled00/util.cpp:635-638
Timestamp: 2026-02-07T16:06:14.651Z
Learning: ESP32-C61, ESP32-C5, and ESP32-P4 all support external PSRAM. Only ESP32-C3, ESP32-C6, and ESP8266 do not support PSRAM and should be excluded from PSRAM-related compilation guards in WLED.

Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/wled_eeprom.cpp:0-0
Timestamp: 2025-09-01T10:26:17.959Z
Learning: In WLED PR `#4876`, the DMXStartLED EEPROM backward compatibility issue was partially addressed by keeping it at address 2550 and reading it as a 16-bit value, with DMXChannelsValue array moved to addresses 2552-2566. This maintains compatibility with pre-0.11 EEPROM layouts for DMXStartLED, though legacy "Set to 255" (code 6) configurations may still need migration logic.

Learnt from: DedeHai
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2026-01-03T16:42:26.035Z
Learning: In WLED, both parallel I2S and single I2S modes require additional DMA buffers (4× the pixel buffer size). The memory calculation must account for which specific buses use I2S hardware, not just check digitalCount <= 8, because single I2S mode places the I2S bus at the END (ESP32 bus 8 with digitalCount=9, S2 bus 4 with digitalCount=5).

@wled wled deleted a comment from coderabbitai bot Feb 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

keep This issue will never become stale/closed automatically magic major This is a non-trivial major feature and will take some time to implement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants